﻿using System;
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ZedGraph;
using System.Threading;
using PFI.DAConv;
using PFI.RegisterDevice;
using PFI.SCHVN;
using Utils.SignalGenerator;
using Utils.RamDevice;

namespace PFI.ADCConv
{
    public class ADC
    {
        public DAC dac { get; private set; }
        public Register reg { get; private set; }
        double currentSignal;
        public bool isCalibrated { get; set; }
        int index;
        bool isCletchingCalibrated;

        public ADC(int quantity, double alphaf, double delta1):
            this(new NotationSystem(quantity, alphaf, delta1))
        {
        }
        public ADC(NotationSystem schvn)
        {
            dac= new DAC(schvn);
            reg = RegisterFactory.Create(schvn);
            isCalibrated=false;

            RAM.Weights.InitRAMWeights(schvn);
        }
        public void SetNewWeights()
        {
            this.dac.schvn.ReCountRealWeigths();
        }

        private void AddOne()
        {
            if(isCalibrated)
            {
                reg.AddOneCalibrated();
            }
            else
            {
                reg.AddOne();
            }
        }
        private void DecOne()
        {
            if(isCalibrated)
            {
                reg.DecOneCalibrated();
            }
            else
            {
                reg.DecOne();
            }
        }
        void CalibationRevisionUp()
        {
            if (isCletchingCalibrated)
            {
                double temp = dac.ZnachenyaR(reg);
                if (RAM.CletchingCombinations.isCletchingCombinationsUp(temp))
                {
                    this.reg.SetPolinom(RAM.CletchingCombinations.GetCletchingCombinationUp(temp));
                }
            }
        }
        void CalibationRevisionDown()
        {
            if (isCletchingCalibrated)
            {
                double temp=dac.ZnachenyaR(reg);
                if (RAM.CletchingCombinations.isCletchingCombinationsDown(temp))
                {
                    this.reg.SetPolinom(RAM.CletchingCombinations.GetCletchingCombinationDown(temp));
                }
            }
        }
        void TrackingSignal(PointPairList adcRes, int beatTime)
        {
                int n = 0;
                while (n < beatTime)
                {
                    if (dac.ZnachenyaC(reg) > currentSignal)
                    {
                        this.DecOne();
                        //CalibationRevisionDown();
                    }
                    else if (dac.ZnachenyaC(reg) < currentSignal)
                    {
                        this.AddOne();
                        //Trace.WriteLine(reg.polinomToString());
                        //CalibationRevisionUp();
                    }
                    adcRes.Add(index, dac.ZnachenyaC(reg));
                    index++;
                    adcRes.Add(index, dac.ZnachenyaC(reg));
                    n++;
                }
        }
        public PointPairList[] GetDiagramOfTransformation(CharacteristoOfTransformationParametrs parametrs,out Dictionary<int,int[]> regTrack)
        {
            reg.SetPolinomNull();

            parametrs.signalSource.Reset();
            currentSignal = 0.0;
            index = 0;

            PointPairList signalGraph = new PointPairList();
            PointPairList adcRes = new PointPairList();
            regTrack = new Dictionary<int, int[]>();

            double AdcDmax = this.reg.GetDmax();

            for (int i = 0; i < parametrs.time && AdcDmax > currentSignal; i++)
            {
                currentSignal = parametrs.signalSource.NextValue();
                //Console.WriteLine(currentSignal);
                signalGraph.Add(index, currentSignal);
                TrackingSignal(adcRes, parametrs.beatTime);
                regTrack.Add(index, this.reg.polinom.Clone() as int[]);
            }
            return new PointPairList[] { signalGraph, adcRes };

        }
        public Register SARAnalogSignal(double signal)
        {
            reg.SetPolinomNull();

            for (int ik1 = dac.schvn.n - 1; ik1 >= 0; ik1--)
            {
                // врівноваження відбувається реальними вагами розрядів, допоки не визначені калібровані ваги
                if (dac.ZnachenyaC(reg.AddBitValue(ik1, 1)) <= signal)
                { }
                else
                    reg.AddBitValue(ik1, 0);
            }

            return reg;
        }
        public Register SARAnalogSignal(double signal, int bannedBit)
        {
            reg.SetPolinomNull();

            for (int ik1 = dac.schvn.n - 1; ik1 >= 0; ik1--)
            {
                // врівноваження відбувається реальними вагами розрядів, допоки не визначені калібровані ваги
                if (dac.ZnachenyaC(reg.AddBitValue(ik1, 1)) <= signal && ik1 != bannedBit)
                { }
                else
                    reg.AddBitValue(ik1, 0);
            }
            return reg;
        }
    }
}
